#include "taskprogressdialog.h"
#include "msgutils.h"
#include <QApplication>
#include <QKeyEvent>
#include <QLabel>
#include <QMessageBox>
#include <QProgressBar>
#include <QPushButton>
#include <QtDebug>
#include <QTimer>
#include <QVBoxLayout>

namespace yc {

TaskProgressDialog::TaskProgressDialog(yc::Task& task, const QString& title, QWidget* parent)
    : TaskProgressDialog(task, title, LeftMessage(), parent)
{
}

TaskProgressDialog::TaskProgressDialog(yc::Task& task, const QString& title,
                                       const LeftMessage& left_message, QWidget* parent)
    : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint), task_(&task), left_message_(left_message)
{
    setAttribute(Qt::WA_DeleteOnClose, true);
    setWindowTitle(title);

    QVBoxLayout* main_layout = new QVBoxLayout(this);
    main_layout->setSizeConstraint(QLayout::SetMaximumSize);
    main_layout->setContentsMargins(10, 10, 10, 10);
    main_layout->setSpacing(10);
    main_layout->addStretch(1);

    QHBoxLayout* hl = new QHBoxLayout;
    hl->setContentsMargins(0, 0, 0, 0);
    hl->setSpacing(0);
    main_layout->addLayout(hl);

    status_label_ = new QLabel(task.statusMessage(), this);
    status_label_->setObjectName("status_message");
    hl->addWidget(status_label_);
    hl->addStretch(1);

    left_label_ = new QLabel(leftMessage(), this);
    left_label_->setObjectName("left_message");
    hl->addWidget(left_label_);

    progress_bar_ = new QProgressBar(this);
    progress_bar_->setObjectName("task_progress");
    int maximum = int(task.evaluateTotalMSecs());
    progress_bar_->setRange(0, qMax(1000, maximum));
    progress_bar_->setTextVisible(false);
    main_layout->addWidget(progress_bar_);
    main_layout->addStretch(1);

    QPushButton* cancel_button = new QPushButton(tr("Cancel"), this);
    cancel_button->setObjectName("normal");
    main_layout->addWidget(cancel_button, 0, Qt::AlignRight);

    cancel_button->setAutoDefault(false);
    cancel_button->setDefault(false);
    connect(cancel_button, &QPushButton::clicked, this, [this] {
        timer_->stop();
        if (task_) {
            disconnect(task_, nullptr, this, nullptr);
            task_->terminate();
        }
        close();
    });

    task.setParent(this);
    connect(task_, &yc::Task::finished, this, &TaskProgressDialog::onFinished);
    connect(task_, &yc::Task::failed, this, &TaskProgressDialog::onFailed);

    timer_ = new QTimer(this);
    timer_->setInterval(500);
    connect(timer_, &QTimer::timeout, this, &TaskProgressDialog::onTimeout);
}

TaskProgressDialog::~TaskProgressDialog()
{
    if (task_) {
        disconnect(task_, nullptr, this, nullptr);
    }
    timer_->stop();
}

int TaskProgressDialog::start()
{
    task_->start();
    if (task_->isFailed() || task_->isFinished()) {
        deleteLater();
        return 0;
    }
    timer_->start();
    return exec();
}

void TaskProgressDialog::keyPressEvent(QKeyEvent* ke)
{
    if (ke->matches(QKeySequence::Close)) {
        return ke->ignore();
    }
    QDialog::keyPressEvent(ke);
}

void TaskProgressDialog::closeEvent(QCloseEvent* ce)
{
    if (task_ && task_->isRunning()) {
        disconnect(task_, nullptr, this, nullptr);
        timer_->stop();
        task_->terminate();
    }
    QDialog::closeEvent(ce);
}

QString TaskProgressDialog::leftMessage() const
{
    if (left_message_) {
        return left_message_();
    } else {
        return QString();
    }
}

void TaskProgressDialog::onTimeout()
{
    // progress
    int elapsed_msecs = int(task_->elapsedMSecs());
    int total_msecs = int(task_->evaluateTotalMSecs());
    int maximum = progress_bar_->maximum();
    int value = progress_bar_->value();
    if (maximum > 0) {
        qreal percent = qreal(value) / qreal(maximum);
        qreal new_percent = qreal(elapsed_msecs) / qreal(total_msecs);
        if (new_percent < percent) {
            new_percent = percent;
        }
        elapsed_msecs = int(total_msecs * new_percent);
    }
    if (elapsed_msecs > 0 && total_msecs >= elapsed_msecs) {
        progress_bar_->setRange(0, total_msecs);
        progress_bar_->setValue(elapsed_msecs);
    }
    // status text
    status_label_->setText(task_->statusMessage());
    left_label_->setText(leftMessage());
}

void TaskProgressDialog::onFinished()
{
    disconnect(task_, nullptr, this, nullptr);
    timer_->stop();
    close();
}

void TaskProgressDialog::onFailed(int /*error*/, const QString& message)
{
    disconnect(task_, nullptr, this, nullptr);
    timer_->stop();
    const QString title = windowTitle();
    QTimer::singleShot(1, qApp, [title, message] {
        msgutils::msgBox(QApplication::activeWindow(), title, message, QMessageBox::Ok,
                         QMessageBox::NoButton, QMessageBox::Warning);
    });
    close();
}
} // namespace yc
